#include "expr.hh"
#include <stack>
#include <cstdlib>
#include <string>

int expr::evaluate(char op, int num1, int num2) {
	switch (op) {
		case '+':
			return num1 + num2;
		case '-':
			return num1 - num2;
		case '*':
			return num1 * num2;
		case '/':
			return num1 / num2;
		case '%':
			return num1 % num2;
		default:
			//assert(0, "unexpected operator");
			_isError = 0;
	}
}
// + - * / ( )
// + -
int expr::calc() {
   if (_s.size() == 0) return 0;
   int start = 0, end = _s.size() - 1;
   stack<int> num;
   stack<char> op;
   int braces = 0; // count the '(' and ')' is match or not
   string s;
   s.clear();
   int once = 1;
   while (start <= end) {
	   char c = _s[start];
	   switch (c) {
		   case '-':
		   case '+': {
			   if (s.size() > 0) {
				   num.push(atoi(s.c_str()));
				   s.clear();
			   }
			   while (op.size() != 0) {
			       char d = op.top();
				   if (d == '(') break;
				   op.pop();
				   //assert(num.size() >=2);
				   int num2 = num.top();
				   num.pop();
				   int num1 = num.top();
				   num.pop();
				   num.push(evaluate(d, num1, num2));
			   }
			   op.push(c);
			   break;
	       }
		   case '0':
		   case '1':
		   case '2':
		   case '3':
		   case '4':
		   case '5':
		   case '6':
		   case '7': 
		   case '8':
		   case '9':
           {
				s += c;
				break;
           }
		   case '*':
		   case '/':
		   case '%':
		        if (s.size() > 0) { 
					num.push(atoi(s.c_str()));
					s.clear();
				}
				while (op.size() != 0) {
			       char d = op.top();
				   if (d != '-' && d != '+' && d != '(') {
					   op.pop();
					   //assert(num.size() >=2);
					   int num2 = num.top();
					   num.pop();
					   int num1 = num.top();
					   num.pop();
					   num.push(evaluate(d, num1, num2));
				   } else break;
			    }
				op.push(c);
		        break;
		   case '(':
				braces++;
				op.push(c);
				break;
		   case ')':
				--braces;
				if (s.size() > 0) {
					num.push(atoi(s.c_str()));
					s.clear();
				}
				once = 1;
				while (op.size() != 0) {
					char d = op.top();
					if (d != '(') {
						op.pop();
						int num2 = num.top();
						num.pop();
						int num1 = num.top();
						num.pop();
						num.push(evaluate(d, num1, num2));
					} else if (once) {
						once--;
						op.pop();
						break;
					}
				}
			   break;
		   case ' ':
			   break;
		   default:
			   _isError = 0;
			   break;
	   }
	   ++start;
   }
   if (s.size() != 0 ) {
	   num.push(atoi(s.c_str()));
	   s.clear();
   } else if (_s[end] != ')') {
	   // missing one number
	   _isError = 1;
	   return 0;
   }
   while (op.size() > 0) {
	   char d= op.top();
	   if (d == '(') {
		   op.pop();
		   continue;
	   }
	   op.pop();
	   int num2 = num.top();
	   num.pop();
	   int num1 = num.top();
	   num.pop();
	   num.push(evaluate(d, num1, num2));
   }
   if (braces != 0) _isError = 1;
   return num.top();

}
